package com.homedo.microservice.open.service.gateway.zuul.task;

import com.google.common.collect.Lists;
import com.homedo.common.util.Detect;
import com.homedo.microservice.open.service.gateway.bean.enums.forroute.StatusEnum4Route;
import com.homedo.microservice.open.service.gateway.bean.enums.forrouteserviceurl.StatusEnum4RouteServiceUrl;
import com.homedo.microservice.open.service.gateway.bean.po.enhanced.RouteEnhanced;
import com.homedo.microservice.open.service.gateway.bean.po.enhanced.RouteServiceUrlEnhanced;
import com.homedo.microservice.open.service.gateway.bean.po.enhanced.RouteVersionEnhanced;
import com.homedo.microservice.open.service.gateway.service.RouteService;
import com.homedo.microservice.open.service.gateway.zuul.conf.RouteConf;
import com.homedo.microservice.open.service.gateway.zuul.conf.ZuulCommonConf;
import com.homedo.microservice.open.service.gateway.zuul.constant.ZuulConstant;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

@Component
public class RouteConfUpdateTask {
    @Autowired
    private ZuulCommonConf zuulCommonConf;
    @Autowired
    private RouteService routeService;

    private static final Logger LOGGER = LoggerFactory.getLogger(RouteConfUpdateTask.class);

    @Scheduled(cron = "0/6 * * * * ?")
    public void routeConfUpdateTask() {
        StopWatch stopWatch = null;
        if (zuulCommonConf.getApplicationLogDetail().get()) {
            stopWatch = new StopWatch();
            stopWatch.start();
            LOGGER.info("更新路由配置开始:时间[" + new DateTime().toString("yyyy-MM-dd HH:mm:ss.SSS") + "]");
        }


        this.doSchedule();

        if (zuulCommonConf.getApplicationLogDetail().get()) {
            if (stopWatch != null) {
                stopWatch.stop();
                LOGGER.info("更新路由配置结束:时间[" + new DateTime().toString("yyyy-MM-dd HH:mm:ss.SSS") + "],耗时[" + stopWatch.getTotalTimeMillis() + "毫秒]");
            }
        }

    }

    private void doSchedule() {
        List<RouteEnhanced> routeEnhanceds = routeService.getEnhanceds4Application(zuulCommonConf.getApplicationName(), Lists.newArrayList(StatusEnum4Route.EFFECTIVE), null);
        if (!Detect.notEmpty(routeEnhanceds)) {
            LOGGER.warn("[{}--没有路由配置，需要检查是否配置异常]", zuulCommonConf.getApplicationName());
        }
        if (routeEnhanceds == null) {
            routeEnhanceds = Lists.newArrayList();
        }

        routeEnhanceds = this.resetRouteEnhanceds(routeEnhanceds);

        this.removeInvalidUrl(routeEnhanceds);//移除失效的url

        Map<String, RouteEnhanced> confsTemp = RouteConf.getInstance().getConfsTemp();

        this.removeNoExistRoute(routeEnhanceds, confsTemp);
        this.updateExistRoute(routeEnhanceds, confsTemp);
        this.addNewRoute(routeEnhanceds, confsTemp);
    }

    private List<RouteEnhanced> resetRouteEnhanceds(List<RouteEnhanced> routeEnhanceds) {
        List<RouteEnhanced> newRouteEnhanceds = Lists.newArrayList();

        routeEnhanceds.forEach(e -> {
            newRouteEnhanceds.addAll(this.resetRouteEnhanceds(e));
        });

        return newRouteEnhanceds;
    }

    private List<RouteEnhanced> resetRouteEnhanceds(RouteEnhanced routeEnhanced) {
        List<RouteEnhanced> newRouteEnhanceds = Lists.newArrayList();
        List<RouteVersionEnhanced> routeVersionEnhanceds = routeEnhanced.getRouteVersionEnhanceds();

        routeEnhanced.setRouteVersionEnhanceds(null);//把子版本号去掉
        newRouteEnhanceds.add(routeEnhanced);


        if (!Detect.notEmpty(routeVersionEnhanceds)) {
            return newRouteEnhanceds;
        }

        routeVersionEnhanceds.forEach(e -> {
            RouteEnhanced newRouteEnhanced = new RouteEnhanced();
            newRouteEnhanced.setId(routeEnhanced.getId() + "_" + e.getId());
            newRouteEnhanced.setApplicationName(routeEnhanced.getApplicationName());
            String path = routeEnhanced.getPath();
            String adjustPath = this.adjustPath(path);

            newRouteEnhanced.setPath("/" + e.getVersion() + ZuulConstant.ZUUL_ROUTE_ADD_PREFIX_SPLIT_PATH + adjustPath);
            newRouteEnhanced.setAddPrefix(routeEnhanced.getAddPrefix());
            newRouteEnhanced.setRouteServiceEnhanced(e.getRouteServiceEnhanced());
            newRouteEnhanced.setStripPrefix(routeEnhanced.getStripPrefix());
            if (Detect.notEmpty(routeEnhanced.getAddPrefix())) {
                newRouteEnhanced.setStripPrefix(true);
                if (!routeEnhanced.getAddPrefix().startsWith("/")) {
                    routeEnhanced.setAddPrefix("/" + routeEnhanced.getAddPrefix());
                }
            }
            newRouteEnhanced.setRetryable(routeEnhanced.getRetryable());
            newRouteEnhanced.setCustomSensitiveHeaders(routeEnhanced.getCustomSensitiveHeaders());
            newRouteEnhanced.setSensitiveHeaders(routeEnhanced.getSensitiveHeaders());
            newRouteEnhanced.setStatus(e.getStatus());
            newRouteEnhanced.setSort(routeEnhanced.getSort() - 1);
            newRouteEnhanced.setRouteDomainEnhanced(routeEnhanced.getRouteDomainEnhanced());
            newRouteEnhanced.setCreateTime(e.getCreateTime());
            newRouteEnhanced.setUpdateTime(e.getUpdateTime());
            newRouteEnhanced.setComment(e.getComment());
            newRouteEnhanced.setAddHostHeader(routeEnhanced.getAddHostHeader());
            //如果有增加即需要对应增加  TODO

            newRouteEnhanceds.add(newRouteEnhanced);
        });


        return newRouteEnhanceds;
    }

    private void removeInvalidUrl(List<RouteEnhanced> routeEnhanceds) {
        routeEnhanceds.forEach(e -> {
            if (e.getRouteServiceEnhanced() != null && Detect.notEmpty(e.getRouteServiceEnhanced().getRouteServiceUrlEnhanceds())) {
                Iterator<RouteServiceUrlEnhanced> routeServiceUrlEnhanceds = e.getRouteServiceEnhanced().getRouteServiceUrlEnhanceds().iterator();
                while (routeServiceUrlEnhanceds.hasNext()) {
                    RouteServiceUrlEnhanced routeServiceUrlEnhanced = routeServiceUrlEnhanceds.next();
                    if (routeServiceUrlEnhanced.getStatus() != StatusEnum4RouteServiceUrl.EFFECTIVE) {
                        routeServiceUrlEnhanceds.remove();
                    }
                }
            }
        });
    }

    private void addNewRoute(List<RouteEnhanced> routeEnhanceds, Map<String, RouteEnhanced> confsTemp) {
        routeEnhanceds.forEach(e -> {
            if (!confsTemp.containsKey(e.getId())) {
                confsTemp.put(e.getId(), e);
            }
        });
    }

    private void updateExistRoute(List<RouteEnhanced> routeEnhanceds, Map<String, RouteEnhanced> confsTemp) {
        confsTemp.entrySet().forEach(e -> {
            String key = e.getKey();
            RouteEnhanced existRouteEnhanced = this.getExist(key, routeEnhanceds);//数据库配置存在
            if (existRouteEnhanced != null) {
                if (!e.getValue().equals(existRouteEnhanced)) {
                    confsTemp.put(key, existRouteEnhanced);
                }
            }
        });
    }

    private void removeNoExistRoute(List<RouteEnhanced> routeEnhanceds, Map<String, RouteEnhanced> confsTemp) {
        //当前生效路由列表中没有即移除当前配置
        confsTemp.entrySet().forEach(e -> {
            String key = e.getKey();

            boolean exist = this.checkExist(key, routeEnhanceds);
            if (!exist) {//数据库配置已不存在
                confsTemp.remove(e.getKey());
//                RouteEnhanced notExist = e.getValue();
//                notExist.setSort(999999D);//放到最后
//                RouteServiceEnhanced routeServiceEnhanced = notExist.getRouteServiceEnhanced();
//                routeServiceEnhanced.setRouteServiceUrlEnhanceds(Lists.newArrayList());//服务地址列表清空
            }
        });
    }

    private boolean checkExist(String key, List<RouteEnhanced> routeEnhanceds) {
        return this.getExist(key, routeEnhanceds) != null;
    }

    private RouteEnhanced getExist(String key, List<RouteEnhanced> routeEnhanceds) {
        for (RouteEnhanced innerRouteEnhanced : routeEnhanceds) {
            if (innerRouteEnhanced.getId().equals(key)) {
                return innerRouteEnhanced;
            }
        }
        return null;
    }

    private String adjustPath(String path) {
        if (path.startsWith("/")) {
            return this.adjustPath(path.substring(1));
        }
        return path;
    }
}
